/* Turska Framework/UI library (Turs2)
 * Copyright 2003-2010 Jetro Lauha
 * All rights reserved.
 * Web: http://iki.fi/jetro/turska/
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of EITHER:
 *   (1) The GNU Lesser General Public License as published by the Free
 *       Software Foundation; either version 2.1 of the License, or (at
 *       your option) any later version. The text of the GNU Lesser
 *       General Public License is included with this library in the
 *       file LICENSE-LGPL.txt.
 *   (2) The BSD-style license that is included with this library in
 *       the file LICENSE-BSD.txt.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
 * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details.
 *
 * $Id: T2GraphicsIrr.h 173 2010-10-21 20:19:30Z jlauha $
 * $Revision: 173 $
 */

#ifndef T2GRAPHICSIRR_H_INCLUDED
#define T2GRAPHICSIRR_H_INCLUDED


namespace irr
{
    class IrrlichtDevice;
    namespace video
    {
        class SMaterial;
    }
}


namespace turska
{
    //! Implementation of Turska Graphics which uses Irrlicht.
    /*! \note Certain patches to the Irrlicht are required, which are
     *        submitted after release of the version 1.4.
     */
    class GraphicsIrr : public turska::Graphics
    {
    public:

        GraphicsIrr(irr::IrrlichtDevice *device, I32 initialMaxBatchSize = 64);
        virtual ~GraphicsIrr() {}

        // From turska::Graphics:

        virtual void beginRender();
        virtual void endRender();

        virtual void setDefaultFlags(UI32 flags) { mDefaultFlags = flags; }

        virtual Image * loadImage(const C8 *fileName,
                                  UI32 flags = G_USE_DEFAULT_FLAGS);

        virtual void flush();

        // GraphicsIrr additions:

        //! Loads and constructs an Image from given irr::io::IReadFile object.
        /*!
         * \param name internal texture name for image.
         * \param file file object to load image from.
         * \param flags image flags to use when loading image.
         *              \sa turska::IMAGE_FLAG
         * \return image object if successful, or 0 if unsuccessful.
         */
        virtual Image * loadImage(const C8 *name, irr::io::IReadFile *file,
                                  UI32 flags = G_USE_DEFAULT_FLAGS);

        //! Constructs an Image from given irr::video::IImage object.
        /*!
         * \param name internal texture name for image.
         * \param image irr source image object to construct Image from.
         * \param dropImage true if source image object should be deleted.
         * \param flags image flags to use when loading image.
         *              \sa turska::IMAGE_FLAG
         * \param sourceRect optional source rectangle to crop from the surface,
         *                   or 0 to use the whole surface.
         * \return image object if successful, or 0 if unsuccessful.
         */
        virtual Image * createImage(const C8 *name,
                                    irr::video::IImage *image, bool dropImage,
                                    UI32 flags,
                                    PixelRectangle *sourceRect = 0);

        //! Loads an irr::video::IImage from given file name.
        /*!
         * \param fileName file name of image to load.
         * \return irr image object if successful, or 0 if unsuccessful.
         */
        virtual irr::video::IImage * loadIrrImage(const C8 *fileName);

        //! Loads an irr::video::IImage from given irr::io::IReadFile object.
        /*!
         * \param file file object to load image from.
         * \return irr image object if successful, or 0 if unsuccessful.
         */
        virtual irr::video::IImage * loadIrrImage(irr::io::IReadFile *file);

        //! Creates an irr::video::ITexture from given irr::video::IImage.
        /*!
         * \param name internal texture name for image.
         * \param oTexture resulting irr::video::ITexture, when successful.
         * \param oUV resulting top-left and bottom-right U,V coordinates
         *            in texture (2 vectors), when successful.
         * \param image irr image to create texture from.
         * \param flags image flags to use when constructing image.
         *              \sa turska::IMAGE_FLAG
         * \param sourceRect optional source rectangle to crop from the surface,
         *                   or 0 to use the whole surface.
         * \return true if successful, or false if unsuccessful.
         */
        virtual bool createTexture(const C8 *name,
                                   irr::video::ITexture *&oTexture,
                                   irr::core::vector2df *oUV,
                                   irr::video::IImage *image,
                                   UI32 flags,
                                   PixelRectangle *sourceRect = 0);

        //! Returns the Irrlicht device.
        irr::IrrlichtDevice * getIrrDevice() { return mIrrDevice; }

        //! Returns the default material.
        const irr::video::SMaterial & getDefaultMaterial()
        {
            return mDefaultMaterial;
        }
        
        void setInitialViewMatrix(const irr::core::matrix4& m) { mInitialViewMatrix = m; }

        #if T2_IRR_API_VERSION < 160
        typedef irr::core::dimension2d<irr::s32> irrdimension2d;
        #else
        typedef irr::core::dimension2d<irr::u32> irrdimension2d;
        #endif

        void prepareBatch(irr::video::ITexture *texture, turska::IMAGE_DRAW_MODE drawMode, UI32 imageFlags, bool forceFlush);
        void batchImageDraw(irr::video::ITexture *texture, turska::IMAGE_DRAW_MODE drawMode, UI32 imageFlags, const irr::video::S3DVertex *vertices);

        irr::core::array<irr::u16> & getBatchIndices() { return mBatchIndices; }
        irr::core::array<irr::video::S3DVertex> & getBatchVertices() { return mBatchVertices; }
        void addToBatchSize(I32 vertexCount, I32 triangleCount) { mCurrentBatchVertexCount += vertexCount; mCurrentBatchTriangleCount += triangleCount; }

    protected:

        irr::core::matrix4 mInitialViewMatrix;

        irr::IrrlichtDevice *mIrrDevice;
        irr::video::IVideoDriver *mIrrDriver;

        irr::video::SMaterial mDefaultMaterial;

        UI32 mDefaultFlags;

        //! Number of primitives in current batch. (Quads consisting of two indexed triangles.)
        I32 mCurrentBatchVertexCount, mCurrentBatchTriangleCount;
        irr::video::ITexture *mCurrentBatchTexture;
        turska::IMAGE_DRAW_MODE mCurrentBatchDrawMode;
        //! Used flags: IF_FILTER_LINEAR, IF_FILTER_LINEAR_MIPMAP, IF_WRAP_CLAMP_EDGE, IF_WRAP_REPEAT
        UI32 mCurrentBatchFlags;

        irr::core::array<irr::u16> mBatchIndices; // 6 indices per primitive (quad)
        irr::core::array<irr::video::S3DVertex> mBatchVertices; // 4 vertices per primitive (quad)

    private:

        // Prevent construction w/out giving Irrlicht device.
        GraphicsIrr();
    }; // GraphicsIrr
} // namespace turska


#endif // !T2GRAPHICSIRR_H_INCLUDED
